{% extends "base.html" %}

{% block title %}KVDB Sentinel Exporter - {{ sentinel_name }} 详情{% endblock %}

{% block extra_css %}
    <style>
        .refresh-timestamp {
            font-size: 0.8rem;
            color: #6c757d;
        }

        .health-status {
            width: 10px;
            height: 10px;
            display: inline-block;
            border-radius: 50%;
            margin-right: 5px;
        }

        .health-good {
            background-color: #28a745;
        }

        .health-warning {
            background-color: #ffc107;
        }

        .health-critical {
            background-color: #dc3545;
        }

        .node-status {
            padding: 0.15rem 0.4rem;
            border-radius: 0.25rem;
            font-size: 0.75rem;
            font-weight: 600;
        }

        .status-master {
            background-color: #e7f5e9;
            color: #28a745;
        }

        .status-slave {
            background-color: #e3f2fd;
            color: #007bff;
        }

        .engine-type {
            font-size: 0.7rem;
            padding: 0.1rem 0.3rem;
            margin-left: 0.3rem;
            border-radius: 0.25rem;
        }

        .engine-redis {
            background-color: #f8d7da;
            color: #721c24;
        }

        .engine-kvrocks {
            background-color: #d1ecf1;
            color: #0c5460;
        }
        
        .engine-pika {
            background-color: #fff3cd;
            color: #856404;
        }
        
        .badge-light-blue {
            background-color: #e3f2fd;
            color: #0d6efd;
        }
        
        .badge-light-purple {
            background-color: #f5e8ff;
            color: #6f42c1;
        }

        .table-redis-nodes th {
            vertical-align: middle;
            white-space: nowrap;
            font-size: 0.85rem;
            padding: 0.4rem;
        }

        .table-redis-nodes td {
            vertical-align: middle;
            font-size: 0.85rem;
            padding: 0.4rem;
        }

        .table-redis-nodes .progress {
            height: 12px;
            margin-bottom: 0;
        }

        .compact-value {
            font-weight: bold;
            font-size: 0.9rem;
        }

        .memory-text {
            font-size: 0.75rem;
        }

        .badge-node-type {
            font-size: 0.7rem;
        }

        .loading-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(255, 255, 255, 0.7);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }
        
        .search-container {
            margin-bottom: 1rem;
        }
        
        .search-input {
            border-radius: 20px;
            padding-left: 2.5rem;
        }
        
        .search-icon {
            position: absolute;
            left: 1.5rem;
            top: 0.7rem;
            color: #6c757d;
        }
        
        .search-clear {
            position: absolute;
            right: 1.5rem;
            top: 0.7rem;
            color: #6c757d;
            cursor: pointer;
        }
        
        .hidden-group {
            display: none;
        }
    </style>
{% endblock %}

{% block content %}
    <div class="d-flex justify-content-between align-items-center mb-3">
        <h2><i class="fa fa-server mr-2"></i>{{ sentinel_name }} 集群信息</h2>
        <div>
            <span class="refresh-timestamp" id="last-refresh">最后更新: 加载中...</span>
            <button class="btn btn-sm btn-outline-primary ml-2" id="refresh-btn">
                <i class="fa fa-refresh mr-1"></i>刷新
            </button>
            <button class="btn btn-sm btn-outline-danger ml-2" id="auto-refresh-btn">
                <i class="fa fa-play mr-1"></i>开启自动刷新
            </button>
        </div>
    </div>

    <div class="row mb-3">
        <div class="col-md-12">
            <div class="alert alert-info py-2">
                <i class="fa fa-info-circle mr-2"></i>
                点击"开启自动刷新"后，页面将每 <strong>{{ refresh_interval }}</strong> 秒自动刷新一次。
                <a href="/{{ sentinel_name }}/metrics" class="alert-link ml-2" target="_blank">
                    <i class="fa fa-external-link"></i> 查看Prometheus指标
                </a>
            </div>
        </div>
    </div>

    <!-- 添加搜索框 -->
    <div class="row mb-3">
        <div class="col-md-12">
            <div class="search-container position-relative">
                <i class="fa fa-search search-icon"></i>
                <input type="text" class="form-control search-input" id="node-search" 
                       placeholder="输入节点组名称或IP:PORT进行搜索" autocomplete="off">
                <i class="fa fa-times search-clear" id="search-clear" style="display: none;"></i>
            </div>
        </div>
    </div>

    <div id="redis-nodes-container">
        <!-- 节点数据将通过AJAX加载 -->
        <div class="text-center py-5">
            <div class="spinner-border text-primary" role="status">
                <span class="sr-only">加载中...</span>
            </div>
            <p class="mt-3">正在加载Redis节点数据...</p>
        </div>
    </div>

    <div id="loading-overlay" class="loading-overlay" style="display: none;">
        <div class="spinner-border text-primary" role="status"></div>
    </div>
{% endblock %}

{% block extra_js %}
    <script>
        // Redis节点数据管理和UI更新
        (function () {
            const sentinelName = "{{ sentinel_name }}";
            const refreshInterval = {{ refresh_interval }} * 1000;  // 转换为毫秒
            let lastRefreshTime = new Date();
            const refreshTimestampEl = document.getElementById('last-refresh');
            const refreshBtn = document.getElementById('refresh-btn');
            const autoRefreshBtn = document.getElementById('auto-refresh-btn');
            const loadingOverlay = document.getElementById('loading-overlay');
            const nodesContainer = document.getElementById('redis-nodes-container');
            const searchInput = document.getElementById('node-search');
            const searchClear = document.getElementById('search-clear');

            let isAutoRefreshEnabled = false; // 默认不自动刷新
            let refreshTimer = null;
            let isFirstLoad = true;
            let allMasterGroups = []; // 存储所有主节点组数据

            // 初始化数据加载
            fetchData();

            // 格式化字节为可读单位
            function formatBytes(bytes) {
                const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
                if (bytes === 0) return '0 B';
                const i = Math.floor(Math.log(bytes) / Math.log(1024));
                const value = bytes / Math.pow(1024, i);
                return `${value.toFixed(2)} ${sizes[i]}`;
            }

            // 更新最后刷新时间显示
            function updateRefreshTimestamp() {
                const now = new Date();
                const diff = Math.floor((now - lastRefreshTime) / 1000);

                if (diff < 60) {
                    refreshTimestampEl.textContent = `最后更新: ${diff} 秒前`;
                } else if (diff < 3600) {
                    refreshTimestampEl.textContent = `最后更新: ${Math.floor(diff / 60)} 分钟前`;
                } else {
                    refreshTimestampEl.textContent = `最后更新: ${Math.floor(diff / 3600)} 小时前`;
                }
            }

            // 获取Redis节点数据
            function fetchData(showLoading = true) {
                if (showLoading && !isFirstLoad) {
                    loadingOverlay.style.display = 'flex';
                }

                fetch(`/${sentinelName}/info/data`)
                    .then(response => {
                        if (!response.ok) {
                            throw new Error('网络响应错误');
                        }
                        return response.json();
                    })
                    .then(data => {
                        allMasterGroups = data; // 保存所有数据
                        renderData(data);
                        lastRefreshTime = new Date();

                        // 设置自动刷新
                        if (isAutoRefreshEnabled) {
                            if (refreshTimer) {
                                clearTimeout(refreshTimer);
                            }
                            refreshTimer = setTimeout(fetchData, refreshInterval);
                        }
                    })
                    .catch(error => {
                        console.error('获取数据失败:', error);
                        nodesContainer.innerHTML =
                            `<div class="alert alert-danger">
                                <i class="fa fa-exclamation-triangle mr-2"></i>
                                获取Redis节点数据失败: ${error.message}
                            </div>`;
                    })
                    .finally(() => {
                        loadingOverlay.style.display = 'none';
                        isFirstLoad = false;
                    });
            }

            // 渲染Redis节点数据
            function renderData(data) {
                const {nodes} = data;

                if (!nodes || nodes.length === 0) {
                    nodesContainer.innerHTML = `
                        <div class="alert alert-warning">
                            <i class="fa fa-exclamation-triangle mr-2"></i>
                            未找到任何Redis节点。请确保Sentinel服务正在运行，并且配置了正确的主节点名称。
                        </div>
                    `;
                    return;
                }

                // 按主节点组名组织数据
                const nodeGroups = {};

                // 将节点按master_name分组
                nodes.forEach(node => {
                    const masterName = node.master_name;
                    if (!nodeGroups[masterName]) {
                        nodeGroups[masterName] = [];
                    }
                    // 只添加主节点
                    if (node.role === 'master') {
                        nodeGroups[masterName].push(node);
                    }
                });

                // 对主节点组进行排序
                const sortedMasterNames = Object.keys(nodeGroups).sort((a, b) => {
                    const aNum = parseInt(a.split('-').pop()) || 0;
                    const bNum = parseInt(b.split('-').pop()) || 0;
                    return aNum - bNum;
                });

                let html = '';

                // 循环渲染每个主节点组
                for (const masterName of sortedMasterNames) {
                    const masterNodes = nodeGroups[masterName];
                    html += `
                        <div class="master-group-container" data-master-name="${masterName}">
                            <div class="card mb-3">
                                <div class="card-header py-2 bg-master">
                                    <h5 class="mb-0">
                                        <i class="fa fa-star mr-1"></i>
                                        主节点组: ${masterName}
                                    </h5>
                                </div>
                                <div class="card-body p-0">
                                    <div class="table-responsive">
                                        <table class="table table-striped table-bordered table-redis-nodes mb-0">
                                            <thead class="thead-light">
                                                <tr>
                                                    <th>节点</th>
                                                    <th>角色</th>
                                                    <th>QPS</th>
                                                    <th>连接数</th>
                                                    <th>总键数</th>
                                                    <th>内存/存储</th>
                                                    <th>版本</th>
                                                    <th>运行时间</th>
                                                </tr>
                                            </thead>
                                            <tbody>
                    `;

                    // 合并主从节点并渲染
                    masterNodes.forEach(masterNode => {
                        // 先渲染主节点
                        html = renderNode('master', masterNode, html);
                        
                        // 然后渲染其对应的从节点
                        if (masterNode.slaves && masterNode.slaves.length > 0) {
                            masterNode.slaves.forEach(slaveNode => {
                                html = renderNode('slave', slaveNode, html);
                            });
                        }
                    });

                    html += `
                                            </tbody>
                                        </table>
                                    </div>
                                </div>
                            </div>
                        </div>
                    `;
                }

                nodesContainer.innerHTML = html;
                
                // 如果有搜索关键字，应用搜索
                if (searchInput.value.trim() !== '') {
                    filterNodes(searchInput.value.trim());
                }
            }
            
            // 渲染单个节点的函数
            function renderNode(role, node, htmlContent) {
                // 使用type字段判断节点类型，而不是is_kvrocks
                // type: 1=Redis, 2=KVRocks, 3=Pika
                const nodeType = node.type || 1; // 默认为Redis
                const isKvrocks = nodeType === 2;
                const isPika = nodeType === 3;
                let memoryPercent = 0;

                if (nodeType === 1 && node.used_memory && node.maxmemory > 0) {
                    memoryPercent = (node.used_memory / node.maxmemory) * 100;
                }
                if (isKvrocks && node.disk_capacity > 0 && node.used_disk_size) {
                    memoryPercent = (node.used_disk_size / node.disk_capacity) * 100;
                }
                if (isPika && node.disk_capacity > 0 && node.used_disk_size) {
                    memoryPercent = (node.used_disk_size / node.disk_capacity) * 100;
                }

                // 获取节点引擎类型名称和CSS类
                let engineTypeClass = 'engine-redis';
                let engineTypeName = 'Redis';
                
                if (isKvrocks) {
                    engineTypeClass = 'engine-kvrocks';
                    engineTypeName = 'KVRocks';
                } else if (isPika) {
                    engineTypeClass = 'engine-pika';
                    engineTypeName = 'Pika';
                }

                // 将新节点HTML添加到现有内容
                let newHtml = htmlContent + `
                    <tr data-node-id="${node.host}:${node.port}">
                        <td>
                            <span class="health-status health-good"
                                  id="health-${node.host}-${node.port}"></span>
                            <strong>${node.host}:${node.port}</strong>
                            <span class="engine-type ${engineTypeClass}">${engineTypeName}</span>
                        </td>
                        <td style="width: 10%">
                            ${role === 'master'
                    ? '<span class="node-status status-master">主节点</span>'
                    : '<span class="node-status status-slave">从节点</span>'
                }
                        </td>
                        <td class="text-center" style="width: 10%">
                            <span class="compact-value"
                                  id="qps-${node.host}-${node.port}">${node.instantaneous_ops_per_sec}</span>
                        </td>
                        <td class="text-center" style="width: 10%">
                            <span class="compact-value">${node.connected_clients}</span>
                        </td>
                        <td class="text-center" style="width: 10%">
                            <span class="compact-value">${node.total_keys}</span>
                        </td>
                        <td style="width: 15%">
                `;

                if (nodeType === 1 && node.used_memory && node.maxmemory > 0) {
                    newHtml += `
                        <div class="d-flex flex-column">
                            <div class="mb-1"><span class="engine-type engine-redis">内存存储</span></div>
                            <div class="progress mb-1">
                                <div class="progress-bar bg-info" role="progressbar"
                                     style="width: ${memoryPercent}%"></div>
                            </div>
                            <div class="d-flex justify-content-between">
                                <span class="memory-text">${node.used_memory_human} / ${node.total_system_memory_human}</span>
                                <span class="memory-text"
                                      id="memory-percent-${node.host}-${node.port}">${memoryPercent.toFixed(1)}%</span>
                            </div>
                        </div>
                    `;
                } else if (isKvrocks || isPika) {
                    const storageTypeName = isKvrocks ? 'KVRocks存储' : 'Pika存储';
                    const storageTypeClass = isKvrocks ? 'engine-kvrocks' : 'engine-pika';
                    
                    newHtml += `
                        <div class="d-flex flex-column">
                            <div class="mb-1"><span class="engine-type ${storageTypeClass}">混合存储</span></div>
                            <div class="progress mb-1">
                                <div class="progress-bar bg-info" role="progressbar"
                                     style="width: ${memoryPercent}%"></div>
                            </div>
                            <div class="d-flex justify-content-between">
                                <span class="memory-text">${formatBytes(node.used_disk_size)} / ${formatBytes(node.disk_capacity)}</span>
                                <span class="memory-text"
                                      id="memory-percent-${node.host}-${node.port}">${memoryPercent.toFixed(1)}%</span>
                            </div>
                        </div>
                    `;
                } else {
                    newHtml += '<span class="text-muted small">未知</span>';
                }

                newHtml += `
                        </td>
                        <td class="text-center" style="width: 10%">
                            ${node.version}
                        </td>
                        <td class="text-center" style="width: 10%">
                            ${node.uptime_in_days} 天
                        </td>
                    </tr>
                `;
                
                return newHtml;
            }

            // 搜索筛选节点
            function filterNodes(keyword) {
                if (!keyword) {
                    // 如果关键字为空，显示所有主节点组
                    document.querySelectorAll('.master-group-container').forEach(el => {
                        el.classList.remove('hidden-group');
                    });
                    searchClear.style.display = 'none';
                    
                    // 移除可能存在的"无结果"提示
                    const noResultsMsg = document.getElementById('no-results-message');
                    if (noResultsMsg) {
                        noResultsMsg.remove();
                    }
                    return;
                }
                
                searchClear.style.display = 'block';
                const keywordLower = keyword.toLowerCase();
                let hasVisibleGroups = false;
                
                // 遍历所有主节点组
                document.querySelectorAll('.master-group-container').forEach(groupEl => {
                    const masterName = groupEl.getAttribute('data-master-name').toLowerCase();
                    let groupVisible = false;
                    
                    // 检查主节点组名称是否匹配
                    if (masterName.includes(keywordLower)) {
                        groupVisible = true;
                    } else {
                        // 检查组内的IP:PORT是否匹配
                        const nodeElements = groupEl.querySelectorAll('tr[data-node-id]');
                        for (const nodeEl of nodeElements) {
                            const nodeId = nodeEl.getAttribute('data-node-id').toLowerCase();
                            if (nodeId.includes(keywordLower)) {
                                groupVisible = true;
                                break;
                            }
                        }
                    }
                    
                    // 设置组的可见性
                    if (groupVisible) {
                        groupEl.classList.remove('hidden-group');
                        hasVisibleGroups = true;
                    } else {
                        groupEl.classList.add('hidden-group');
                    }
                });
                
                // 如果没有匹配的组，显示提示信息
                if (!hasVisibleGroups) {
                    // 先移除可能存在的"无结果"提示
                    const noResultsMsg = document.getElementById('no-results-message');
                    if (noResultsMsg) {
                        noResultsMsg.remove();
                    }
                    
                    // 创建并添加新的提示信息元素
                    const noResultsElement = document.createElement('div');
                    noResultsElement.className = 'alert alert-info mt-3';
                    noResultsElement.id = 'no-results-message';
                    noResultsElement.innerHTML = `
                        <i class="fa fa-info-circle mr-2"></i>
                        未找到匹配 "${keyword}" 的节点组或节点
                    `;
                    nodesContainer.appendChild(noResultsElement);
                } else {
                    // 移除可能存在的"无结果"提示
                    const noResultsMsg = document.getElementById('no-results-message');
                    if (noResultsMsg) {
                        noResultsMsg.remove();
                    }
                }
            }

            // 切换自动刷新状态
            function toggleAutoRefresh() {
                isAutoRefreshEnabled = !isAutoRefreshEnabled;
                if (isAutoRefreshEnabled) {
                    fetchData(false);
                    autoRefreshBtn.innerHTML = '<i class="fa fa-pause mr-1"></i>暂停自动刷新';
                    autoRefreshBtn.classList.remove('btn-outline-danger');
                    autoRefreshBtn.classList.add('btn-outline-success');
                } else {
                    if (refreshTimer) {
                        clearTimeout(refreshTimer);
                    }
                    autoRefreshBtn.innerHTML = '<i class="fa fa-play mr-1"></i>开启自动刷新';
                    autoRefreshBtn.classList.remove('btn-outline-success');
                    autoRefreshBtn.classList.add('btn-outline-danger');
                }
            }

            // 每秒更新显示的时间
            setInterval(updateRefreshTimestamp, 1000);

            // 手动刷新按钮
            refreshBtn.addEventListener('click', function () {
                fetchData(true);
            });

            // 自动刷新切换按钮
            autoRefreshBtn.addEventListener('click', toggleAutoRefresh);
            
            // 搜索框输入事件
            searchInput.addEventListener('input', function() {
                const keyword = this.value.trim();
                filterNodes(keyword);
            });
            
            // 清除搜索按钮
            searchClear.addEventListener('click', function() {
                searchInput.value = '';
                filterNodes('');
                this.style.display = 'none';
            });
        })();
    </script>
{% endblock %}